import { BadRequestException, Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { dirname, extname, join } from 'path';
import { createReadStream, promises } from 'fs';

import { Store } from './entities/store.entity';
import { calculateFilePathHash } from 'src/utils';

@Injectable()
export class StoreService {
  constructor(
    @InjectRepository(Store)
    private readonly storeRepository: Repository<Store>,
  ) {}

  async uploadFile(file: Express.Multer.File) {
    const id = await calculateFilePathHash(file.path, 'sha256');

    const ext = extname(file.originalname);
    const newPath = join(dirname(file.path), `${id}${ext}`);

    await promises.rename(file.path, newPath);

    let store = await this.storeRepository.findOne({ where: { id } });

    if (store) {
      throw new BadRequestException('文件已存在');
    }

    store = new Store();
    store.id = id;
    store.name = Buffer.from(file.originalname, 'binary').toString();
    store.type = ext;

    return this.storeRepository.save(store);
  }

  async uploadFiles(files: Array<Express.Multer.File>) {
    return Promise.all(files.map((file) => this.uploadFile(file)));
  }

  async deleteFile(id: string) {
    const file = await this.storeRepository.findOne({ where: { id } });

    if (!file) {
      throw new NotFoundException('文件不存在');
    }

    // 文件路径
    const filePath = join(process.cwd(), 'static/store', `${id}${file.type}`);

    try {
      await promises.unlink(filePath);
    } catch (err) {
      // 文件可能已经被删除
      if (err.code !== 'ENOENT') {
        throw new BadRequestException('文件删除失败');
      }
    }

    await this.storeRepository.delete(id);

    return { message: '文件已删除', id };
  }

  async downloadFile(id: string) {
    const file = await this.storeRepository.findOne({ where: { id } });

    if (!file) {
      throw new NotFoundException('文件不存在');
    }

    const filePath = join(process.cwd(), 'static/store', `${id}${file.type}`);

    try {
      await promises.access(filePath);
    } catch {
      throw new NotFoundException('文件已丢失或路径错误');
    }

    const stream = createReadStream(filePath);

    return { file, stream };
  }

  async findAll(current: number = 1, pageSize: number = 10) {
    const [data, total] = await this.storeRepository.findAndCount({
      skip: (current - 1) * pageSize,
      take: pageSize,
      order: { update_time: 'DESC' }, // 可选，按id倒序
    });

    return {
      data,
      total,
      current,
      pageSize,
      pages: Math.ceil(total / pageSize),
    };
  }

  async findOne(id: string) {
    const file = await this.storeRepository.findOne({ where: { id } });

    if (!file) {
      throw new BadRequestException('文件不存在');
    }

    return file;
  }

  async paginate(current: number = 1, pageSize: number = 10) {
    const queryBuilder = this.storeRepository.createQueryBuilder('store');

    // 可以拼接复杂条件
    queryBuilder
      // .leftJoinAndSelect('user.profile', 'profile')
      // .where('user.isActive = :isActive', { isActive: true })
      .orderBy('store.update_time', 'DESC')
      .skip((current - 1) * pageSize)
      .take(pageSize);

    const [data, total] = await queryBuilder.getManyAndCount();

    return {
      data,
      total,
      current,
      pageSize,
      pages: Math.ceil(total / pageSize),
    };
  }
}
